/**
  * The contents of this file are subject to the Mozilla Public
  * License Version 1.1 (the "License"); you may not use this file
  * except in compliance with the License. You may obtain a copy of
  * the License at http://www.mozilla.org/MPL/
  * 
  * Software distributed under the License is distributed on an "AS
  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  * implied. See the License for the specific language governing
  * rights and limitations under the License.
  * 
  * The Original Code is "The JSP Documentation Generator of Alex Muc".
  * 
  * The Initial Developer of the Original Code is <a href="mailto:alex.muc@utoronto.ca">Alex Muc</a>.
  * Portions created by <a href="mailto:alex.muc@utoronto.ca">Alex Muc</a>
  * are Copyright (C) 2000 <a href="mailto:alex.muc@utoronto.ca">Alex Muc</a>.
  * All Rights Reserved.
  * 
  * Contributor(s): Alex Muc
  **/


package com.thoughtservice.jspdoc;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.Future;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.gagawa.java.Document;
import com.hp.gagawa.java.DocumentType;
import com.hp.gagawa.java.elements.Div;
import com.hp.gagawa.java.elements.Li;
import com.hp.gagawa.java.elements.Ul;
import com.thoughtservice.jspdoc.customize.Customizer;
import com.thoughtservice.jspdoc.executors.JSPDocExecutor;
import com.thoughtservice.jspdoc.json.JSONGenerator;
import com.thoughtservice.jspdoc.output.GenerateD3Structure;
import com.thoughtservice.jspdoc.output.GenerateHtmlDoc;
import com.thoughtservice.jspdoc.output.GenerateHtmlStructure;
import com.thoughtservice.jspdoc.output.IndexNameEnum;
import com.thoughtservice.jspdoc.output.JSPPageEnum;
import com.thoughtservice.jspdoc.utils.GenerateUtils;


/**
 * Write the documentation for a JSP page.  This will create an HTML
 * file with all the information that was extracted about the JSP page.
 * This includes writing the following information about the page:
 * <ul>
 *  <li>Name</li>
 *  <li>Description</li>
 *  <li>Import statements</li>
 *  <li>Error page</li>
 *  <li>Parameters used on this page (name, type, and description)</li>
 *  <li>HTML links to other pages</li>
 *  <li>HTML links to this page from other pages</li>
 *  <li>Static includes of other pages</li>
 *  <li>Static includes of this page from other pages</li>
 *  <li>Dynamic includes of other pages</li>
 *  <li>Dynamic includes of this page from other pages</li>
 *  <li>Redirects to other pages</li>
 * </ul>
 * 
 * @author Alex Muc 
 */
public class DirTree {


	private static Logger LOG = LoggerFactory.getLogger(DirTree.class);
	/**
	 * The list of jsp files to process.
	 */
	protected JSPFileList jspFileList;

	/**
	 * The Customizer used to modify the output of the documentation generator
	 * for your specific site.
	 */
	private Customizer customizer;

	/**
	 * The top level of the jsp source directory tree.
	 */
	public static String rootSourceDir;

	/**
	 * The directory where the output will go
	 */
	protected String rootOutputDir;

	/**
	 * Initialize the JSPDoc generator system.
	 */
	public DirTree(Customizer c) {
		super();

		rootSourceDir = "";

		customizer = c;
	}

	
	/**
	 * Write the documentation for a JSP page.  This will create an HTML
	 * file with all the information that was extracted about the JSP page.
	 * This includes writing the following information about the page:
	 * <ul>
	 *  <li>Name</li>
	 *  <li>Description</li>
	 *  <li>Import statements</li>
	 *  <li>Error page</li>
	 *  <li>Parameters used on this page (name, type, and description)</li>
	 *  <li>HTML links to other pages</li>
	 *  <li>HTML links to this page from other pages</li>
	 *  <li>Static includes of other pages</li>
	 *  <li>Static includes of this page from other pages</li>
	 *  <li>Dynamic includes of other pages</li>
	 *  <li>Dynamic includes of this page from other pages</li>
	 *  <li>Redirects to other pages</li>
	 *  <li>Tiles inserted in page</li>
	 *  <li>Tile inserts in page</li>
	 * </ul>
	 * 
	 * @param p ca.yourdecor.jspdoc.JSPPage The JSPPage to write the documentation for.
	 */
	protected void outputPage(JSPPage p, GenerateHtmlStructure htmlStructure) {
		
		if ( ! p.isPage()) {
			return;
		}

		try {		

			String justName = p.getName().substring(rootSourceDir.length() + 1, p.getName().length());
			RE re = new RE("\\.jsp$");
			String justJSPName = new String(justName);
			justName = re.subst(justName, ".html");
			File f = new File(rootOutputDir, "/docs/" + justName);
			PrintWriter pw = new PrintWriter(new FileWriter(f));

			// Create the HTML header
			Document document = new Document(DocumentType.XHTMLTransitional);
			//Copy js scripts 
			htmlStructure.copyScriptsAndStyles();
            
			htmlStructure.createDocumentHead(p, document, IndexNameEnum.INDEX_BY_PAGE_NAME);	
			

			document.body.appendText(htmlStructure.getGenerationInfo());

			// Build the directory hierarchy

			// Table container definition
			Div contentContainerDiv = new Div();
			contentContainerDiv.setCSSClass("contentContainer");
			
							
			
			//htmlStructure.outputLinksBar(p, pw);
			//pw.write(htmlStructure.outputNextGenLinksBar(GenerateUtils.getRootRelPath(p.getName(), RootSourceDir), IndexNameEnum.INDEX_BY_PAGE_NAME).write());
			
			//header <div>
			Div headerClass = new Div();
			headerClass.setCSSClass("header");
			headerClass.appendText("<h2>" + justJSPName + "</h2>\n");
			
			document.body.appendChild(headerClass);
			//pw.write("<h2>" + justJSPName + "</h2>\n");

			//hook up d3
			String relativePath = GenerateUtils.getRootRelPath(p.getName(), rootSourceDir);
			
			int height = 55;
			JSONGenerator jsonGenerator = new JSONGenerator(p,p.getNameShort(), p.getTileInsertsIn(), p.getStaticIncludes(), p.getDynamicIncludes(), jspFileList);
			//Provide height to alter d3 rendered data height
			height = (p.getTypeSize(JSPPageEnum.TILE_INSERTS_INPAGE) * 55)
					+ (p.getTypeSize(JSPPageEnum.S_INCLUDES) * 55)
					+ (p.getTypeSize(JSPPageEnum.S_INCLUDES) * 55);
			height = height == 55 || height == 0  ? 55:height;
			
			GenerateD3Structure d3Structure = new GenerateD3Structure(jsonGenerator.getJson(), relativePath, height);
			
			document.body.appendChild(d3Structure.getHead());
			document.body.appendChild(d3Structure.getBody());

			// Output the Description
			/*pw.write("<b>Description</b><br>\n");
			if (p.getPageDesc() != null) {
				pw.write(p.getPageDesc());
			}
			pw.write(separator);
			pw.write("<hr>");*/						

			if(p.getPageDesc() != null){
				document.body.appendText(htmlStructure.getHeaderDiv("Description", p.getPageDesc()));
			}			
			
			GenerateHtmlDoc htmlDoc = new GenerateHtmlDoc(rootSourceDir, jspFileList);
			
			
			
			//Wrap all tables inside <ul><li>'s
			Ul blockListUl = new Ul();
			blockListUl.setCSSClass("blockList");
			
			Li blockListImportsLi = new Li();
			blockListImportsLi.setCSSClass("blockList");
			
			//Output the tile entries Used as tile In
			
			if(p.getTypeSize(JSPPageEnum.TILE_INSERTS) > 0){
				Li blockListTilesLi = new Li();
				blockListTilesLi.setCSSClass("blockList");			
				blockListTilesLi.appendChild(htmlDoc.outputTilesInserts(p, p.getTileInserts(), pw, JSPPage.TILE_INSERTS));
				blockListUl.appendChild(blockListTilesLi);		
			}
			
			//Output the tile inserts in entries
			if(p.getTypeSize(JSPPageEnum.TILE_INSERTS_INPAGE) > 0){
				Li blockListTilesInLi = new Li();
				blockListTilesInLi.setCSSClass("blockList");			
				blockListTilesInLi.appendChild(htmlDoc.outputTilesInsertsIn(p, p.getTileInsertsIn(), pw, JSPPage.TILE_INSERTS_INPAGE));
				blockListUl.appendChild(blockListTilesInLi);		
			}
			
			// Output the Imports
			if(p.getTypeSize(JSPPageEnum.IMPORTS) > 0){
				blockListImportsLi.appendChild(htmlDoc.outputImports(p, p.getImports(), pw));	
				blockListUl.appendChild(blockListImportsLi);
			}

			// Output the ErrorPage
			htmlDoc.outputConnections("Error Page", p, p.getConnections(JSPPage.ERRORPAGE), pw, JSPPage.ERRORPAGE);
			//pw.write(separator);

			// Output the Parameters
			if(p.getTypeSize(JSPPageEnum.PARAMETERS) > 0){
				Li blockListParametersLi = new Li();
				blockListParametersLi.setCSSClass("blockList");			
				blockListParametersLi.appendChild(htmlDoc.outputParameters(p, pw));
				blockListUl.appendChild(blockListParametersLi);
			}
			//pw.write(separator);

			// Output the LinkTo
			if(p.getTypeSize(JSPPageEnum.LINKS_TO) > 0){
				Li blockListLinksToLi = new Li();
				blockListLinksToLi.setCSSClass("blockList");			
				blockListLinksToLi.appendChild(htmlDoc.outputConnections("Links To", p, p.getConnections(JSPPage.LINKSTO), pw, JSPPage.LINKSTO));
				blockListUl.appendChild(blockListLinksToLi);
			}
			//pw.write(separator);

			// Output the LinkToForm
			if(p.getTypeSize(JSPPageEnum.LINKSTOFORM) > 0){
				Li blockListLinksToFormLi = new Li();
				blockListLinksToFormLi.setCSSClass("blockList");			
				blockListLinksToFormLi.appendChild(htmlDoc.outputConnections("Form Link To", p, p.getConnections(JSPPage.LINKSTOFORM), pw, JSPPage.LINKSTOFORM));
				blockListUl.appendChild(blockListLinksToFormLi);
			}
			//pw.write(separator);

			// Output the LinkFrom
			if(p.getTypeSize(JSPPageEnum.LINKSFROM) > 0){
				Li blockListLinksFromLi = new Li();
				blockListLinksFromLi.setCSSClass("blockList");			
				blockListLinksFromLi.appendChild(htmlDoc.outputConnections("Links From", p, p.getConnections(JSPPage.LINKSFROM), pw, JSPPage.LINKSFROM));
				blockListUl.appendChild(blockListLinksFromLi);
			}

			// Output the static includes
			if(p.getTypeSize(JSPPageEnum.S_INCLUDES) > 0){
				Li blockListStaticIncludesLi = new Li();
				blockListStaticIncludesLi.setCSSClass("blockList");			
				blockListStaticIncludesLi.appendChild(htmlDoc.outputConnections("Statically Includes", p, p.getConnections(JSPPage.S_INCLUDES), pw, JSPPage.S_INCLUDES));
				blockListUl.appendChild(blockListStaticIncludesLi);
			}
			//pw.write(separator);

			// Output the static included in
			if(p.getTypeSize(JSPPageEnum.S_INCLUDEDIN) > 0){
				Li blockListStaticIncludesInLi = new Li();
				blockListStaticIncludesInLi.setCSSClass("blockList");			
				blockListStaticIncludesInLi.appendChild(htmlDoc.outputConnections("Statically Included In", p, p.getConnections(JSPPage.S_INCLUDEDIN), pw, JSPPage.S_INCLUDEDIN));
				blockListUl.appendChild(blockListStaticIncludesInLi);
			}			

			// Output the dynamic includes
			if(p.getTypeSize(JSPPageEnum.D_INCLUDES) > 0){
				Li blockListDynamicIncludesLi = new Li();
				blockListDynamicIncludesLi.setCSSClass("blockList");			
				blockListDynamicIncludesLi.appendChild(htmlDoc.outputConnections("Dynamically Includes", p, p.getConnections(JSPPage.D_INCLUDES), pw, JSPPage.D_INCLUDES));
				blockListUl.appendChild(blockListDynamicIncludesLi);
			}			
			
			// Output the dynamic included in
			if(p.getTypeSize(JSPPageEnum.D_INCLUDEDIN) > 0){
				Li blockListDynamicIncludesInLi = new Li();
				blockListDynamicIncludesInLi.setCSSClass("blockList");			
				blockListDynamicIncludesInLi.appendChild(htmlDoc.outputConnections("Dynamically Included In", p, p.getConnections(JSPPage.D_INCLUDEDIN), pw, JSPPage.D_INCLUDEDIN));
				blockListUl.appendChild(blockListDynamicIncludesInLi);
			}			

			// Output the redirects
			if(p.getTypeSize(JSPPageEnum.REDIRECTS) > 0){
				Li blockListRedirectsLi = new Li();
				blockListRedirectsLi.setCSSClass("blockList");			
				blockListRedirectsLi.appendChild(htmlDoc.outputConnections("Redirects To", p, p.getConnections(JSPPage.REDIRECTS), pw, JSPPage.REDIRECTS));
				blockListUl.appendChild(blockListRedirectsLi);
			}
						
			contentContainerDiv.appendChild(blockListUl);
			document.body.appendChild(contentContainerDiv);					
					
			//Legal copy
			document.body.appendChild(htmlStructure.createLegalCopy());
			
			pw.write(document.write());
		

			pw.flush();
			pw.close();
		} catch (IOException e) {
			LOG.error("{}", ExceptionUtils.getFullStackTrace(e));
		} catch (RESyntaxException e) {
			LOG.error("{}", ExceptionUtils.getFullStackTrace(e));
		}

	}


	
	



	/**
	 * Extract documentation out of the JSP page.  This is the main workhorse for this
	 * documentations system.  It will look for documentation in the JSP page.
	 * 
	 * @param p ca.yourdecor.jspdoc.JSPPage The page to extract documentation from.
	 */
	protected void processPage(JSPPage p) {

		LOG.trace("Entering {}", "processPage");
		// Get page contents into a string
		String pc = new String();
		String line;
		try {
			BufferedReader br = new BufferedReader(new FileReader(p.getName()));
			while ((line = br.readLine()) != null) {
				pc += line;
			}
		} catch (FileNotFoundException e) {
			LOG.error("Can't find file: {}", p.getName());
		} catch (IOException e) {
			LOG.error("Can't read file: {}", p.getName());
		}

		//Candidate for executor service
		
		try {
			
			JSPDocExecutor executor = new JSPDocExecutor(p, jspFileList, pc, rootSourceDir);
			List<Future<Object>> futures = executor.processExecutors();
			
			
			/*// Look for page import			
			new ProcessPageImports(p, pc);

            // Get errorPage
            new ProcessErrorPage(p, pc, FileList);

			// Look for page description
			//new ProcessPageDescription(p, pc);

			// Look for parameters 
			new ProcessAllParams(p, pc);

			// Look for LinksTo
			new ProcessLinksTo(p, pc, FileList);

			// Look for LinksToForm
			new ProcessLinksToForm(p, pc);
			
			//Look for <form
			new ProcessForm(p, pc);

			// Look for Static Includes
			new ProcessStaticIncludes(p, pc, FileList);

			// Look for Dynamic Includes 
			new ProcessDynamicIncludes(p, pc, FileList);

			//Look for redirects
			new ProcessRedirects(p, pc);
			
			//Look for tiles:insert
			new ProcessTileInserts(p, pc, FileList, RootSourceDir); 
			
			//Look for tiles:insert in current JSP page
			new ProcessTileInsertsIn(p, pc, FileList, RootSourceDir); */

			
		} catch (Exception e) {
			LOG.error("{}", ExceptionUtils.getFullStackTrace(e));

		}

	}
		
}
